package com.ra.landlord;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.da.finance.DaFinanceStatement;
import com.googlecode.cswish.annotation.Protected;
import com.googlecode.cswish.annotation.Rest;
import com.googlecode.cswish.exception.ApplicationException;
import com.googlecode.cswish.model.PageInfo;
import com.googlecode.cswish.oosearch.Condition;
import com.googlecode.cswish.oosearch.QLInfo;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.struts.spring.ObjectFactory;
import com.opensymphony.xwork2.ActionContext;
import com.ra.external.FinanceStatementService;
import com.ra.landlord.constant.FeeRuleCalcMode;
import com.ra.landlord.constant.FeeRuleType;
import com.ra.landlord.constant.LandlordConstant;
import com.ra.order.rental.RentalOrder;
import com.ra.order.rental.RentalOrderService;
import com.ra.system.Version;
import com.ra.util.DateTimeUtil;
import com.ra.util.PrinterService;

@Service
public class FeeService {
	
	private static final Log logger = LogFactory.getLog(FeeService.class);

	@Resource
	private GenericService genericService;
	
	@Resource
	private FeeAdditionService feeAdditionService;
	
	@Resource
	private LandlordUserService landlordUserService;
	
	@Resource
	private PrinterService printerService;
	
	@Resource
	private FeeRecordService feeRecordService;
	
	@Resource
	private RentalOrderService rentalOrderService;
	
	@Resource
	private FinanceStatementService financeStatementService;
	
	@Resource
	private RoomService roomService;
	
	@Resource
	private MeterService meterService;
	
	private FeeService feeService;
	
	private FeeService getThis() {
		if (feeService == null) {
			feeService = ObjectFactory.getInstance().getBean(FeeService.class, false);
		}
		return feeService;
	}
	
	@PersistenceContext(unitName="espirit")
	protected EntityManager em;
	
	@Transactional
	@Rest(type="add")
	public Fee add(Fee model) {
		Room dbRoom = genericService.load(model.getRoom());
		model.setTenantUser(dbRoom.getAgreement().getTenantUser());
		return genericService.add(model);
	}
	
	/**
	 * 创建费用
	 * @param model
	 * @return
	 */
	@Transactional
	@Rest(type="add")
	public Fee addFee(Fee model) {
		LandlordUser landlordUser = landlordUserService.getLoginUser();
		model.setLandlordUser(landlordUser.getOwnerUser());
		//待定?
		model.setType(1);
		model.setAgent(landlordUser.getOwnerUser());
		return genericService.add(model);
	}
	
	/**
	 * 删除费用，逻辑删除
	 * @param model
	 * @return
	 */
	@Rest(type="delete")
	public Fee deleteFee(Fee model) {
		Fee fee = genericService.load(model);
		fee.setStatus(0);
		fee = genericService.merge(fee);
		
		//删除未收租里持久化的费用
		feeRecordService.deleteFeeRecordByRoom(fee.getRoom());
		
		//删除该费用生成的财务流水
		financeStatementService.deleteWithFee(fee);
		if (fee.getRoom().getAgreement() != null) {
			getOrGenerateFeeRecordIfNotExists(fee.getRoom().getAgreement());
		}
		meterService.repaireOneRoomMeterFee(fee.getRoom());
		return fee;
	}
	
	/**
	 * 验证费用对应的订单是否已经支付，或关闭
	 * @param model
	 * @return
	 */
	private Integer getOrderStatus(Fee model){
		Integer result = null;
		if (model.getFeeRecordId() != null) {
			FeeRecord feeRecord = new FeeRecord();
			feeRecord.setId(model.getFeeRecordId());
			RentalOrder rentalOrder = rentalOrderService.searchRentalOrderByFeeRecord(feeRecord);
			if (rentalOrder != null) {
				result = rentalOrder.getOrderState();
			}
		}
		return result;
	}
	
	/**
	 * 确认收租
	 * @param model
	 * @return
	 * @throws ParseException 
	 */
	@Rest(type="update")
	public Fee updateFee(Fee model) throws ParseException {
		
		Integer orderStatus = getOrderStatus(model);
		
		if (orderStatus != null) {
			if (orderStatus == RentalOrder.ORDER_STATE_PAYING) {
				throw new ApplicationException("该租客正在网上支付中，请稍后刷新未收租页面！");
			}else if(orderStatus == RentalOrder.ORDER_STATE_SUCCESS
					|| orderStatus == RentalOrder.ORDER_STATE_PAYMENTED){
				throw new ApplicationException("该租客已网上支付，请刷新未收租页面！");
			}
		}
		
		BigDecimal depositRecv = null;
		Room dbRoom = genericService.load(model.getRoom());
		List<Fee> fees = dbRoom.getFees();
		if (fees == null || fees.size() == 0) {
			depositRecv = model.getRental();
			generateDepositFee(dbRoom.getAgreement(), depositRecv, depositRecv);
		}
		
		Fee resultFee = updateFeeOriginal(model);
		
		//收租后更新FeeRecord
		feeRecordService.updateFeeRecordAfterRent(resultFee);
		
		return resultFee;
	}
	
	/**
	 * 确认收租
	 * @param model
	 * @return
	 * @throws ParseException 
	 */
	@Transactional
	@Rest(type="update")
	public Fee updateFeeOriginal(Fee model) {
		Fee fee = null;
		List<FeeAddition> lstNewAddition = model.getFeeAdditions();
		LandlordUser landlordUser = model.getLandlordUser();
		if(landlordUser == null) {
			landlordUser = landlordUserService.getLoginUser();
		}
		if (model.getId() != null) {
			fee = genericService.load(model);
			List<FeeAddition> lstOldAddition = fee.getFeeAdditions();
			//设置新的附加费用
			if (lstOldAddition != null && lstNewAddition != null) {
				for (FeeAddition feeOldAddition : lstOldAddition) {
					for (FeeAddition feeNewAddition : lstNewAddition) {
						if(feeOldAddition != null && feeOldAddition.getId() != null && feeNewAddition != null && feeNewAddition.getId() != null){
							if(feeOldAddition.getId().compareTo(feeNewAddition.getId()) == 0){
								feeOldAddition.setPriceActual(feeNewAddition.getPriceActual());
							}
						}
					}
				}
				//修改已经计算好的额外费用
				//genericService.merge(lstOldAddition);
			}
		}else{
			fee = new Fee();
			fee.setLandlordUser(landlordUser.getOwnerUser());
			fee.setRoom(genericService.load(model.getRoom()));
			fee.setTenantUser(genericService.load(model.getTenantUser()));
		}
		
		fee.setLandlordUser(landlordUser.getOwnerUser());
		fee.setAgent(landlordUser.getOwnerUser());
		fee.setDateActual(DateTimeUtil.DATETIME_FORMAT.format(Calendar.getInstance().getTime()));
		fee.setRemark(model.getRemark());
		fee.setPayMode(model.getPayMode());
		fee.setAmountActual(model.getAmountActual().setScale(2,BigDecimal.ROUND_HALF_UP));
		fee.setAmountRecv(model.getAmountRecv().setScale(2,BigDecimal.ROUND_HALF_UP));
		fee.setBalance(model.getBalance().setScale(2,BigDecimal.ROUND_HALF_UP));
		fee.setRental(model.getRental().setScale(2,BigDecimal.ROUND_HALF_UP));
		fee.setDateBeginRecv(DateTimeUtil.completeDateTime(model.getDateBeginRecv())); 
		fee.setDateEndRecv(DateTimeUtil.completeDateTime(model.getDateEndRecv()));	 
		//默认为1，和confirmed重复了	 
		fee.setType(1);
		//和PC同步，用status=1表示费用已确认
		fee.setStatus(LandlordConstant.FEE_STATE_CONFIRMED);
		fee.setAgreement(fee.getRoom().getAgreement());
		fee.setFeeType(Fee.FEE_TYPE_RENTAL);
		// the RentapartmentEntityInterceptor will set the version if the version is null
		//Integer version = fee.getVersion() == null ? 0 : fee.getVersion();
		//fee.setVersion(++version);
		Fee resultFee = genericService.merge(fee);
		financeStatementService.autoCreateFinanceStatement(resultFee);
		
		if (model.getId() == null && lstNewAddition != null) {
			for (FeeAddition feeAddition : lstNewAddition) {
				
				feeAddition.setFee(resultFee);
				FeeRuleCfg feeRuleCfg = genericService.load(feeAddition.getFeeRuleCfg());
				feeAddition.setFeeRuleCfg(feeRuleCfg);
				if (feeRuleCfg.getFeeRuleCfgDesc().getType() == FeeRuleType.fixed) {
					Meter meter = new Meter();
					meter.setId(2);
					feeAddition.setMeter1(meter);
					feeAddition.setMeter2(meter);
				}else if(feeRuleCfg.getFeeRuleCfgDesc().getType() == FeeRuleType.meter){
					Meter meter1 = genericService.load(feeAddition.getMeter1());
					Meter meter2 = genericService.load(feeAddition.getMeter2());
					
					if(meter1 == null){
						if(meter2 == null){
							Meter meter = new Meter();
							meter.setId(0);
							meter1 = meter;
							meter2 = meter;
						}else{
							meter1 = meter2;
						}
					}
					feeAddition.setMeter1(meter1);
					feeAddition.setMeter2(meter2);
				}
				if (feeAddition.getPriceActual() == null) {
					feeAddition.setPriceActual(feeAddition.getPriceRecv());
				}
				feeAddition.setPriceActual(feeAddition.getPriceActual().setScale(2,BigDecimal.ROUND_HALF_UP));
				if (feeAddition.getPriceRecv() == null) {
					feeAddition.setPriceRecv(feeAddition.getPriceActual());
				}
				feeAddition.setOverdueFine(false);
				feeAddition.setLandlordUser(landlordUser.getOwnerUser());
				feeAddition.setId(null);
				
				genericService.merge(feeAddition);
			}
		}
		return resultFee;
	}
	
	
	/**
	 * 查询费用
	 * @return
	 */
	@Rest(type = "search")
	public List<Fee> searchFee(Fee fee){
		String strShort = "id"; 
		String strOrderBy = "DESC";
		fee.setStatus(Version.STATUS_VALID);
		PageInfo<Fee> pageInfo = this.genericService.search(fee, 0, 100, strShort, strOrderBy, false, null, null, true, false);
		return pageInfo.getData();
	}
	
	/**
	 * 补全ra_fee数据中的agreement_id（用于修改PC端的数据）
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public String completeFeeData(){
		List<Fee> lstFee = null;
		SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String 
		ql = "select a from " + Fee.class.getName()+" a where a.agreement is null";
		lstFee = genericService.searchByQl(new QLInfo(ql, null), false).getData();
		int num = 0;
		if (lstFee != null) {
			//List<Object> newFee = new ArrayList<>();
			for (Fee fee : lstFee) {
				boolean updateFlag = false;
				Room room = fee.getRoom();
				try {
					List<Agreement> lstAgreement = room.getAgreements();
					String begin = fee.getDateBeginRecv();
					String end = fee.getDateEndRecv();
					Date feeBeginDate = DateTimeUtil.StrToDate(begin, f);
					Date feeEndDate = DateTimeUtil.StrToDate(end, f);
					
					if (begin.length() < 19) {
						fee.setDateBeginRecv(DateTimeUtil.formatDateTime(feeBeginDate, null));
						fee.setDateEndRecv(DateTimeUtil.formatDateTime(feeEndDate, null));
						updateFlag = true;
					}
					
					String dateActual = fee.getDateActual();
					if(StringUtils.isNotBlank(dateActual)){
						if (dateActual.length() < 19) {
							Date feeActualDate = DateTimeUtil.StrToDate(dateActual, f);
							fee.setDateActual(DateTimeUtil.formatDateTime(feeActualDate, null));
							updateFlag = true;
						}
					}
					
					if(fee.getAgreement() == null){
						for (Agreement agreement : lstAgreement) {
							
							if(agreement.getTenantUser().getId().equals(fee.getTenantUser().getId())){
								fee.setAgreement(agreement);
								updateFlag = true;
								num++;
								break;
							}
							
							Date agreementBeginDate = DateTimeUtil.StrToDate(agreement.getRentBeginDate(), f);
							Date agreementEndDate = DateTimeUtil.StrToDate(agreement.getRentEndDate(), f);
							//合同的开始时间早于费用的开始时间&&合同的结束时间晚于费用的开始时间
							//合同的开始时间早于费用的结束时间&&合同的结束时间晚于费用的结束时间
							//合同的开始时间等于费用的结束时间
							if ((agreementBeginDate.before(feeBeginDate) && agreementEndDate
									.after(feeBeginDate))
									|| (agreementBeginDate.before(feeEndDate) && agreementEndDate
											.after(feeEndDate))
									|| agreementBeginDate.equals(feeBeginDate)) {
								fee.setAgreement(agreement);
								updateFlag = true;
								num++;
								break;
							}
							
							
						}
					}
					
					if(updateFlag){
						try {
							//genericService.merge(fee);
							if (logger.isDebugEnabled()) {
								if (fee.getAgreement() != null) {
									logger.debug("-----------费用（"+fee.getId()+"）添加agreement_id:"+fee.getAgreement().getId());
								}else{
									logger.debug("-----------只修改了日期格式（"+fee.getId()+"）------17位修改为19为--"+fee.getDateBeginRecv());
								}
							}
						} catch (Exception e) {
							logger.debug("---------------------------------------------补全合同ID和修正日期格式出现问题--fee.id:"+fee.getId(),e);
						}
						//newFee.add(fee);
						genericService.update(fee);
					}
				} catch (Exception e) {
					e.printStackTrace();
					continue;
				}
			}
			//genericService.updateList(newFee);
		}
		
		return "共修改费用："+num+"条";
	}
	
	/**
	 * 收租打印票据数据
	 * @return
	 */
	@Rest(type = "search")
	public Fee showReceiptView(Fee fee){
//		Fee obj = new Fee();
//		obj.setId(1);
//		obj.setDateBeginRecv("2014-08-10 11:11:11");
//		obj.setDateEndRecv("2014-09-10 11:11:11");
//		TenantUser tenantUser = new TenantUser();
//		tenantUser.setId(1);
//		tenantUser.setName("张三");
//		obj.setTenantUser(tenantUser);
//		Room room = new Room();
//		room.setId(11);
//		room.setName("A1004");
//		Building building = new Building();
//		building.setId(11);
//		building.setName("北方大厦");
//		room.setBuilding(building);
//		Agreement agreement = new Agreement();
//		agreement.setId(101);
//		agreement.setAgreementState(1);
//		List lst = new ArrayList();
//		lst.add(agreement);
//		room.setAgreements(lst);
//		Meter currentMeter = new Meter();
//		currentMeter.setCount(BigDecimal.valueOf(100.0));
//		room.setCurrentMeter(currentMeter);
//		
//		List<FeeAddition> feeAdditions = new ArrayList<FeeAddition>();
//		FeeAddition feeAddition = new FeeAddition();
//		FeeRuleCfg feeRuleCfg = new FeeRuleCfg();
//		FeeRuleCfgDesc feeRuleCfgDesc = new FeeRuleCfgDesc();
//		feeRuleCfgDesc.setName("水表");
//		feeRuleCfgDesc.setType(FeeRuleType.meter);
//		feeRuleCfg.setFeeRuleCfgDesc(feeRuleCfgDesc);
//		feeAddition.setFeeRuleCfg(feeRuleCfg);
//		Meter meter1 = new Meter();
//		meter1.setCount(BigDecimal.valueOf(100));
//		
//		Meter meter2 = new Meter();
//		meter2.setCount(BigDecimal.valueOf(50));
//		feeAddition.setMeter1(meter1);
//		feeAddition.setMeter2(meter2);
//		feeAddition.setPriceActual(BigDecimal.valueOf(50));
//		feeAdditions.add(feeAddition);
//		
//		//obj.setFeeAdditions(feeAdditions);
//		obj.setRoom(room);
//		obj.setRemark("this is remark");
//		obj.setDateActual("2014-09-28 12:12:10");
//		obj.setRental(BigDecimal.valueOf(1000.0));
//		obj.setAmountRecv(BigDecimal.valueOf(1050.0));
//		obj.setAmountActual(BigDecimal.valueOf(1050.0));
//		LandlordUser landlordUser = new LandlordUser();
//		landlordUser.setId(111);
//		landlordUser.setName("超人");
//		obj.setLandlordUser(landlordUser);
//		return obj;
		return genericService.load(fee);
	}
	
	@Rest(type = "print")
	public String printReceiptView(Fee fee, int width, int height){
		String url = "/ra/landlord/fee.showReceiptView.html?fee.id=" + fee.getId();
		if (width <= 0) {
			width = 375;
		}
		return printerService.convertUrlToImage(url, width, height, 1);
	}
	
	@Rest(type = "print")
	public String printTempReceiptView(Room room, int width, int height){
		String url = "/ra/landlord/fee.showTempReceiptView.html?model.id=" + room.getId();
		if (width == 0) {
			width = 375;
		}
		return printerService.convertUrlToImage(url, width, height, 1);
	}
	
	/**
	 * 打印未收租的费用票据
	 * @param room
	 * @return
	 */
	
	@Rest(type = "print")
	public Fee showTempReceiptView(Room model){
		Fee resultFee = null;
		Room room = genericService.load(model);
		if (room != null) {
			List<Fee> fees = room.getFees();
			if (fees != null && fees.size() > 0) {
				Fee lastFee = fees.get(fees.size()-1);
				// 附加费
				resultFee = calculateNewFee(lastFee,room);
				resultFee.setRoom(lastFee.getRoom());
				resultFee.setTenantUser(lastFee.getTenantUser());
			}
		}
		return resultFee;
	}
	
	/**
	 * 计算单个房间的待收费用
	 * 
	 * @param room
	 * @return
	 */
	
	@Rest(type = "calculate")
	public Fee calculateFee(Room room) {
		
		Fee resultFee = null;
		//如果有未付的Fees，直接返回第一条fee记录
		List<Fee> unpayFees = room.getUnpayFees();
		List<Fee> fees = room.getFees();
		List<Fee> agreementFees = room.getAgreement().getFees();
		if (room.getRentState() == LandlordConstant.RENT_STATE_BOOK) {
			resultFee = new Fee();
			resultFee.setAmountRecv(room.getAgreement().getRentPay());
		}
		if (unpayFees != null && unpayFees.size() > 0) {
			//若是通过手动生成费用，或者出租生成费用（房租、押金），将会执行此段代码
			//是否需要设置未付费用的附加费（比如水费电费。。。）
			return unpayFees.get(0);
		}else if(agreementFees != null && agreementFees.size() == 1){
			//相当于只有一条押金费用
			//计算该合同内的第一个月的费用
			Fee lastFee = fees.get(fees.size()-1);
			resultFee = calculateNewFee(lastFee,room);
		}else if(agreementFees != null && agreementFees.size() > 1){
			
			Fee lastFee = agreementFees.get(0);
			// 附加费
			List<FeeAddition> feeAdditions = new ArrayList<FeeAddition>();
			Date date = DateTimeUtil.StrToDate(lastFee.getDateEndRecv());
			if (date == null || date.compareTo(new Date()) >= 0){
				FeeAddition feeAddition = new FeeAddition();
				feeAddition.setFee(lastFee);
				feeAdditions = feeAdditionService.searchFeeAddition(feeAddition);
				lastFee.setFeeAdditions(feeAdditions);
				resultFee = lastFee;
			}else{
				// 临时计算费用
				// search all the agreement & list them	
				resultFee = calculateNewFee(lastFee,room);
			}
	 	}
		return resultFee;
	}
	
	/**
	 * 计算单个房间下一次的待收费用（不管该房间本期是否已经收过租了）
	 * 返回值为什么用List<Room>,是考虑前端展示，未收租费用详情也是这个返回值，保证前端可用一个模板
	 * @param room
	 * @return
	 */
	@Rest(type = "calculate")
	public List<Room> calculateNextFee(int roomid) {
		Room model = new Room();
		model.setId(roomid);
		Room dbRoom = roomService._collectRental(model);
		List<Room> rooms = new ArrayList<Room>(1);
		rooms.add(dbRoom);
		return rooms;
		/*List<Room> rooms = new ArrayList<Room>();
		Fee resultFee = null;
		Room room = genericService.load(Room.class, roomid);
		if (room != null) {
			List<Fee> fees = room.getFees();
			if (fees != null && fees.size() > 0) {
				Fee lastFee = fees.get(fees.size()-1);
				// 附加费
				resultFee = calculateNewFee(lastFee,room);
				room.setReceivableFee(resultFee);
			}
			rooms.add(room);
		}
		return rooms;*/
	}
	
	/**
	 * 计算一个新的费用，当费用未生成时，可通过该方法进行生成
	 * @param lastFee
	 * @param room
	 * @return
	 */
	@Rest(type = "calculate")
	public Fee calculateNewFee(Fee lastFee, Room room){
		// 附加费
		List<FeeAddition> feeAdditions = new ArrayList<FeeAddition>();
		
		// 临时计算费用
		// search all the agreement & list them	
		Fee fee = new Fee();
		BigDecimal balance = null;
		if (lastFee != null) {
			// 获取费用开始时间，结束时间
			Agreement agreement = room.getAgreement();
			List<Fee> agreementFees = agreement.getFees();
			balance = lastFee.getBalance();
			if (agreementFees != null && agreementFees.size() > 0) {
				Calendar calendar = Calendar.getInstance();
				String dateStartRecv = "";
				if (agreementFees.size() == 1) {
					dateStartRecv = agreement.getRentBeginDate();
				}else{
					room.setLastFee(lastFee);
					// 这次费用的开始时间 = 上一次费用结束日期的后一天时间作为
					dateStartRecv = DateTimeUtil.getSpecifiedDayAfter(lastFee.getDateEndRecv());;
				}
				fee.setDateBeginRecv(dateStartRecv);
				calendar.setTime(DateTimeUtil.StrToDate(dateStartRecv,DateTimeUtil.DATETIME_FORMAT));
				//rent_cycle=0表示1个月，=1表示2个月   
				calendar.set(Calendar.MONTH,
						calendar.get(Calendar.MONTH) + agreement.getRentCycle() + 1);
				int day = calendar.get(Calendar.DATE);
				calendar.set(Calendar.DATE, day - 1);
				String dateEndRecv = DateTimeUtil.formatDate(calendar.getTime());
				fee.setDateEndRecv(dateEndRecv);
			}
		}
		
		// 出租周期
		BigDecimal rentCycle = new BigDecimal(1);
		if (room.getAgreement().getRentCycle() != null) {
			int iCycle = room.getAgreement().getRentCycle() + 1 ;
			rentCycle = new BigDecimal(iCycle);
		}
		
		// 租金
		BigDecimal monthRental = new BigDecimal(0);
		if(StringUtils.isNotBlank(room.getRental())){
			monthRental = new BigDecimal(room.getRental());
		}else{
			monthRental = room.getAgreement().getRentPay();
		}
		
		BigDecimal amount = monthRental.multiply(rentCycle);
		BigDecimal rental = amount.add(new BigDecimal(0));
		
		for (FeeRule feeRule : room.getFeeRules()) {
			FeeRuleCfg feeRuleCfg = feeRule.getFeeRuleCfg();
			
			if (feeRuleCfg != null) {
				FeeAddition feeAddition = new FeeAddition();
				//设置额外费用对应的费用规则
				feeAddition.setFeeRuleCfg(feeRuleCfg);
				
				FeeRuleCfgDesc feeRuleCfgDesc = feeRuleCfg.getFeeRuleCfgDesc();
				FeeRuleCfgCalc feeRuleCfgCalc = feeRuleCfg.getFeeRuleCfgCalc();

				if (feeRuleCfgDesc.getType() == FeeRuleType.fixed) { // 固定费用
					
					if (feeRuleCfgDesc.getCalcMode() == FeeRuleCalcMode.normal) {
						feeAddition.setPriceRecv(feeRuleCfgCalc.getPrice());
					} else if (feeRuleCfgDesc.getCalcMode() == FeeRuleCalcMode.areaFactor) {
						BigDecimal price = room.getArea().multiply(feeRuleCfgCalc.getPrice());
						feeAddition.setPriceRecv(price);
					} else {
						feeAddition.setPriceRecv(feeRuleCfgCalc.getPrice());
					}
				} else {	// 水电计算公式
					Meter meter1 = feeRule.getMeter(0);
					Meter meter2 = feeRule.getMeter(1);
					if (meter1 != null && meter2 != null) {
						feeAddition.setMeter1(meter1);
						feeAddition.setMeter2(meter2);
						BigDecimal gap = null;
						
						gap = meter1.getCount().subtract(meter2.getCount());
						
						if (feeRuleCfgDesc.getCalcMode() == FeeRuleCalcMode.threshold) {	// 门限
							if (gap != null && feeRuleCfgCalc.getValueLow() != null 
									&& gap.subtract(feeRuleCfgCalc.getValueLow()).compareTo(BigDecimal.ZERO) < 0) {
								gap = feeRuleCfgCalc.getValueLow();
							}
						}
						
						BigDecimal price = gap.multiply(meter1.getPrice());
						feeAddition.setPriceRecv(price);
					}
					
				}
				if (feeAddition.getPriceRecv() != null) {
					amount = amount.add(feeAddition.getPriceRecv());
				}
				feeAdditions.add(feeAddition);
			}
			
			
		}
		
		//计算公摊费用
		if (room.getRoomShareUnits() != null) {
			for (RoomShareUnit roomShareUnit : room.getRoomShareUnits()) {
				ShareUnit shareUnit = roomShareUnit.getShareUnit();
				
				String shareProportion = getShareProportion(roomShareUnit);
				
				String[] proportion = shareProportion.split("/");
				BigDecimal numerrtor = new BigDecimal(proportion[0]);
				BigDecimal denominator = new BigDecimal(proportion[1]);
				
				
				List<FeeRule> feeRules = shareUnit.getFeeRules();
				if (feeRules != null && feeRules.size() > 0) {
					for (FeeRule feeRule : feeRules) {
						FeeRuleCfg feeRuleCfg = feeRule.getFeeRuleCfg();
						FeeAddition feeAddition = new FeeAddition();
						//设置额外费用对应的费用规则
						feeAddition.setFeeRuleCfg(feeRuleCfg);
						FeeRuleCfgDesc feeRuleCfgDesc = feeRuleCfg.getFeeRuleCfgDesc();
						FeeRuleCfgCalc feeRuleCfgCalc = feeRuleCfg.getFeeRuleCfgCalc();
						boolean isShare = feeRuleCfgDesc.getIsShare() == null ? false : feeRuleCfgDesc.getIsShare();
						if (isShare && feeRuleCfgDesc.getType() == FeeRuleType.meter){
							Meter meter1 = feeRule.getMeter(0);
							Meter meter2 = feeRule.getMeter(1);
							if (meter1 != null && meter2 != null) {
								feeAddition.setMeter1(meter1);
								feeAddition.setMeter2(meter2);
								BigDecimal gap = null;
								
								gap = meter1.getCount().subtract(meter2.getCount());
								
								if (feeRuleCfgDesc.getCalcMode() == FeeRuleCalcMode.threshold) {	// 门限
									if (gap.subtract(feeRuleCfgCalc.getValueLow()).compareTo(BigDecimal.ZERO) < 0) {
										gap = feeRuleCfgCalc.getValueLow();
									}
								}
								
								BigDecimal amountPrice = gap.multiply(meter1.getPrice());
								
								BigDecimal price = amountPrice.multiply(numerrtor).divide(denominator, 2, BigDecimal.ROUND_HALF_UP).setScale(2,BigDecimal.ROUND_HALF_UP);
								
								feeAddition.setPriceRecv(price);
								if (numerrtor.intValue() == 0) {
									amountPrice = new BigDecimal(0);
								}
								feeAddition.setShareAmount(amountPrice.setScale(2,BigDecimal.ROUND_HALF_UP));
							}
						}
						if (feeAddition.getPriceRecv() != null) {
							amount = amount.add(feeAddition.getPriceRecv());
						}
						feeAdditions.add(feeAddition);
					}
				}
			}
		}
		
		fee.setRental(rental);
		fee.setFeeAdditions(feeAdditions);
		// 应收应该合并余额
		if (balance != null) {
			amount = amount.subtract(balance);
		}
		fee.setAmountRecv(amount);
		return fee;
	}
	
	/**
	 * 获取公摊占比,如1/3
	 * @param roomShareUnit
	 * @return
	 */
	private String getShareProportion(RoomShareUnit roomShareUnit){
		String result = "0/1";
		Room masterRoom = roomShareUnit.getRoom();
		List<Fee> selfFees = masterRoom.getAgreement().getFees();
		BigDecimal totalDays = new BigDecimal(0);
		if (selfFees.size() > 1) {
			Fee selfFee = selfFees.get(0);
			BigDecimal ownIntervalDays = new BigDecimal(DateTimeUtil.getIntervalDays(selfFee.getDateBeginRecv(), selfFee.getDateEndRecv()));
			ShareUnit shareUnit = roomShareUnit.getShareUnit();
			List<RoomShareUnit> roomShareUnits = shareUnit.getRoomShareUnits();
			if (roomShareUnits != null && roomShareUnits.size() > 0) {
				for (RoomShareUnit tempRoomShareUnit : roomShareUnits) {
					Room room = tempRoomShareUnit.getRoom();
					ValidAgreement agreement = room.getAgreement();
					if (agreement != null) {
						List<Fee> fees = agreement.getFees();
						if (fees.size() > 1) {
							Fee compareFee = fees.get(0);
							String strSelfDateEndRecv = DateTimeUtil.formatStringDate(selfFee.getDateEndRecv(), DateTimeUtil.ISO_DATE_FORMAT);
							for (Fee fee : fees) {
								// 找统一收费结束时间的费用记录
								String strCompareDateEndRecv = DateTimeUtil.formatStringDate(fee.getDateEndRecv(), DateTimeUtil.ISO_DATE_FORMAT);
								if (strSelfDateEndRecv.equals(strCompareDateEndRecv)) {
									compareFee = fee;
								}
							}
							BigDecimal intervalDays = new BigDecimal(DateTimeUtil.getIntervalDays(compareFee.getDateBeginRecv(), compareFee.getDateEndRecv()));
							totalDays = totalDays.add(intervalDays);
						}
					}
				}
			}
			if (totalDays.intValue() != 0) {
				result = ownIntervalDays + "/" + totalDays;
			}
		}
		
		return result;
	}
	/**
	 * 查询一年内的
	 * @param roomId
	 * @return
	 * @throws Exception 
	 * @throws IllegalAccessException 
	 */
	
	@Rest(type = "search")
	public List<Fee> _searchRoomHasPaidFee(Room model) throws IllegalAccessException, Exception {
		Room dbRoom = genericService.load(model);
		ActionContext.getContext().getValueStack().set("model", dbRoom);
		Calendar prevYear = Calendar.getInstance();
		prevYear.add(Calendar.YEAR, -1);
		QLInfo qlInfo = new QLInfo("select a from Fee a where a.status != 0 and a.room.id = ? and str_to_date(dateEndRecv, '%Y-%m-%d %H:%i:%s') > ? order by a.id desc", false, model.getId(), prevYear.getTime());
		
		List<Fee> fees = genericService.searchByQl(qlInfo).getData(); 
		for (int i = 0; i < fees.size(); i++) {
			fees.get(i).setRentAmountActual(fees.get(i).getRental());
			if (fees.get(i).getRentalCalc() != null) {
				fees.get(i).setRentAmountRecv(fees.get(i).getRentalCalc());
			} else {
				List<FeeAddition> feeAddtions = fees.get(i).getFeeAdditions();
				BigDecimal amountRecv = BigDecimal.valueOf(0);
				if (feeAddtions != null) {
					for (FeeAddition feeAddition : feeAddtions) {
						amountRecv = amountRecv.add(feeAddition.getPriceRecv());
					}
				}
				if ( (i + 1) < fees.size() && fees.get(i + 1).getBalance() != null) {
					amountRecv = amountRecv.add(fees.get(i + 1).getBalance());
				}
				fees.get(i).setRentAmountRecv(fees.get(i).getAmountRecv().subtract(amountRecv));
			}
			
		}
		return fees;
	}
	
	public Fee print(Fee model, Boolean isDeposit) {
		Fee dbFee = genericService.load(model);
		if (dbFee.getAgreement().getFees().size() > 1) {
			BigDecimal dbPrevBalance = dbFee.getAgreement().getFees().get(1).getBalance();
			if (dbPrevBalance == null) {
				dbPrevBalance = BigDecimal.valueOf(0);
			}
			ActionContext.getContext().getValueStack().set("prevBalance", dbPrevBalance);
		}
		if (!isDeposit) {
			List<FeeAddition> feeAddtions = dbFee.getFeeAdditions();
			BigDecimal amountActual = BigDecimal.valueOf(0);
			for (FeeAddition feeAddition : feeAddtions) {
				amountActual = amountActual.add(feeAddition.getPriceActual());
			}
			dbFee.setRentAmountActual(dbFee.getAmountRecv().subtract(amountActual));
			dbFee.setRentAmountRecv(dbFee.getRental());
		}
		return dbFee;
	}
	
	/**
	 * 产生feeRecord
	 * @param model
	 */
	public FeeRecord generateFeeRecord(Room model) {
		if (model.getAgreement() == null || !Room.RENT_STATE_ALREADY.equals(model.getRentState())) {
			return null;
		}
		Meter fixedMeter = genericService.load(Meter.class, 2);
		FeeRecord feeRecord = new FeeRecord();
		feeRecord.setRoom(model);
		feeRecord.setAgreement(model.getAgreement());
		feeRecord.setTenantUser(model.getAgreement().getTenantUser());
		feeRecord.setLandlordUser(landlordUserService.getLoginUser().getOwnerUser());
		feeRecord.setAgent(landlordUserService.getLoginUser());
		feeRecord.setStatus(FeeRecord.FEE_STATUS_RENT_TODO);
		if (model.getRental() != null) {
			feeRecord.setRental(BigDecimal.valueOf(Double.valueOf(model.getRental())));
		} else {
			feeRecord.setRental(model.getAgreement().getRentPay());
		}
		
		int monthCycle = model.getAgreement().getRentCycle() + 1;
		if (model.getAgreement().getFees() != null && model.getAgreement().getFees().size() > 1) {
			feeRecord.setDateBeginRecv(DateTimeUtil.getSpecifiedDayAfter(model.getAgreement().getFees().get(0).getDateEndRecv()));
			
		} else {
			if (model.getAgreement().getPayNum() != null) {
				monthCycle = model.getAgreement().getPayNum();
			}
			feeRecord.setDateBeginRecv(model.getAgreement().getRentBeginDate());
		}
		
		feeRecord.setDateEndRecv(DateTimeUtil.getFeeEndDate(feeRecord.getDateBeginRecv(), monthCycle));
		feeRecord.setRental(feeRecord.getRental().multiply(BigDecimal.valueOf(monthCycle)).setScale(2, RoundingMode.HALF_UP));
		feeRecord.setRentalCalc(feeRecord.getRental());
		BigDecimal amount = feeRecord.getRental();
		
		List<FeeAdditionRecord> feeAdditionRecords = new ArrayList<FeeAdditionRecord>(model.getFeeRules().size());
		feeRecord.setFeeAdditionRecords(feeAdditionRecords);
		for (FeeRule feeRule : model.getFeeRules()) {
			FeeRuleCfgCalc feeRuleCfgCalc = feeRule.getFeeRuleCfg().getFeeRuleCfgCalc();
			FeeRuleCfgDesc feeRuleCfgDesc = feeRule.getFeeRuleCfg().getFeeRuleCfgDesc();
			FeeAdditionRecord feeAdditionRecord = new FeeAdditionRecord();
			feeAdditionRecord.setStatus(FeeAdditionRecord.STATUS_CONFIRMED);
			feeAdditionRecord.setFeeRuleCfg(feeRule.getFeeRuleCfg());

			if (feeRuleCfgDesc.getType() == FeeRuleType.fixed) {
				if (Room.RENT_TYPE_ENTIRE.equals(model.getRentType())) {
					if (feeRuleCfgDesc.getCalcMode() == FeeRuleCalcMode.areaFactor) {
						feeAdditionRecord.setPriceRecv(model.getArea().multiply(feeRuleCfgCalc.getPrice()));
					} else {
						feeAdditionRecord.setPriceRecv(feeRuleCfgCalc.getPrice());
					}
					feeAdditionRecord.setPriceRecv(feeAdditionRecord.getPriceRecv().multiply(BigDecimal.valueOf(monthCycle)));
					amount = amount.add(feeAdditionRecord.getPriceRecv());
				} else {
					//TODO 分租固定费用处理
				}
				feeAdditionRecord.setMeter1(fixedMeter);
				feeAdditionRecord.setMeter2(fixedMeter);
				feeAdditionRecords.add(feeAdditionRecord);
			} else if (feeRuleCfgDesc.getType() == FeeRuleType.meter) {
				//创建一次抄表记录。
				Meter emptyMeter = feeRule.getMeter(0);
				if (emptyMeter == null) {
					emptyMeter = genericService.load(Meter.class, 0);
				}
				feeAdditionRecord.setPriceRecv(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));
				feeAdditionRecord.setMeter1(emptyMeter);
				feeAdditionRecord.setMeter2(emptyMeter);
				feeAdditionRecords.add(feeAdditionRecord);
			}
		}
		if (model.getAgreement().getFees() != null && model.getAgreement().getFees().size() > 0) {
			amount = amount.subtract(model.getAgreement().getFees().get(0).getBalance());
		}
		feeRecord.setAmountRecv(amount);
		return genericService.add(feeRecord);
	}
	
	@Transactional
	public Fee collectRental(Fee model, List<FeeAddition> extraFee, BigDecimal depositRecv, BigDecimal depositActual) {
		Integer orderStatus = getOrderStatus(model);
		if (orderStatus != null) {
			if (orderStatus == RentalOrder.ORDER_STATE_PAYING) {
				throw new ApplicationException("该租客正在网上支付中，请稍后刷新未收租页面！");
			}else if(orderStatus == RentalOrder.ORDER_STATE_SUCCESS || orderStatus == RentalOrder.ORDER_STATE_PAYMENTED){
				throw new ApplicationException("该租客已网上支付，请刷新未收租页面！");
			}
		}
		Room dbRoom = genericService.load(model.getRoom());
		if (depositActual != null && depositRecv != null) {
			model.setAmountRecv(model.getAmountRecv().subtract(depositActual));
			model.setAmountActual(model.getAmountActual().subtract(depositActual));
			generateDepositFee(dbRoom.getAgreement(), depositRecv, depositActual);
		}
		
		model.setBalance(model.getBalance().setScale(2, RoundingMode.HALF_UP));
		model.setRental(model.getRental().setScale(2, RoundingMode.HALF_UP));
		model.setDateBeginRecv(DateTimeUtil.completeDateTime(model.getDateBeginRecv()));
		model.setDateEndRecv(DateTimeUtil.completeDateTime(model.getDateEndRecv()));
		model.setAgreement(dbRoom.getAgreement());
		model.setTenantUser(dbRoom.getAgreement().getTenantUser());
		model.setLandlordUser(landlordUserService.getLoginUser().getOwnerUser());
		model.setAgent(landlordUserService.getLoginUser());
		model.setDateActual(DateTimeUtil.formatDate(new Date()));
		model.setId(null);
		
		//兼容vc
		model.setType(1);
		model.setStatus(LandlordConstant.FEE_STATE_CONFIRMED);
		
		if (model.getFeeAdditions() != null && model.getFeeAdditions().size() > 0) {
			for (FeeAddition feeAddition : model.getFeeAdditions()) {
				feeAddition.setOverdueFine(false);
				feeAddition.setLandlordUser(landlordUserService.getLoginUser().getOwnerUser());
				feeAddition.setId(null);
			}
		}
		if (model.getFeeAdditions() == null) {
			model.setFeeAdditions(new ArrayList<FeeAddition>());
		}
		if (extraFee != null && extraFee.size() > 0) {
			FeeRuleCfg extraFeeRuleCfg = genericService.load(FeeRuleCfg.class, FeeRuleCfg.FEE_RULE_CFG_EXTRA);
			Meter fixedMeter = genericService.load(Meter.class, 2);
			
			for (FeeAddition feeAddition : extraFee) {
				feeAddition.setPriceActual(feeAddition.getPriceActual().setScale(2, RoundingMode.HALF_UP));
				feeAddition.setPriceRecv(feeAddition.getPriceActual());
				feeAddition.setFeeRuleCfg(extraFeeRuleCfg);
				feeAddition.setMeter1(fixedMeter);
				feeAddition.setMeter2(fixedMeter);
				feeAddition.setOverdueFine(false);
				feeAddition.setLandlordUser(landlordUserService.getLoginUser().getOwnerUser());
				feeAddition.setId(null);
				feeAddition.setStatus(FeeAddition.STATUS_CONFIRMED);
				model.getFeeAdditions().add(feeAddition);
			}
		}
		
		model.setAmountRecv(model.getAmountRecv().setScale(2, RoundingMode.HALF_UP));
		model.setFeeType(Fee.FEE_TYPE_RENTAL);
		Fee dbFee = genericService.add(model);
		financeStatementService.autoCreateFinanceStatement(dbFee);
		//收租后更新FeeRecord 状态
		FeeRecord example = new FeeRecord();
		example.setAgreement(dbRoom.getAgreement());
		example.setStatus(FeeRecord.FEE_STATUS_RENT_TODO);
		List<FeeRecord> feeRecords = genericService.searchByModel(example, Condition.DEFAULT).getData();
		for (FeeRecord feeRecord : feeRecords) {
			feeRecord.setStatus(FeeRecord.FEE_STATUS_RENT_DONE);
			genericService.merge(feeRecord);
		}
		genericService.refresh(dbRoom);
		getOrGenerateFeeRecordIfNotExists(dbRoom.getAgreement());//收完租后产生下个月的代缴费。
		
		if (model.getFeeRecordId() != null && model.getFeeRecordId()!= 0) {
			//更改未完成订单的状态
			FeeRecord feeRecordExample = new FeeRecord();
			feeRecordExample.setId(model.getFeeRecordId());
			RentalOrder rentalOrderExample = new RentalOrder();
			rentalOrderExample.setFeeRecord(feeRecordExample);
			rentalOrderExample.setOrderState(RentalOrder.ORDER_STATE_WAITING_PAYMENT);
			RentalOrder dbRentalOrder = genericService.searchByModel(rentalOrderExample, Condition.DEFAULT).getData(0);
			if (dbRentalOrder != null) {
				dbRentalOrder.setOrderState(RentalOrder.ORDER_STATE_SUCCESS);
				genericService.merge(dbRentalOrder);
			}
		}
		return dbFee;
	}
	
	public Fee generateDepositFee(ValidAgreement agreement, BigDecimal depositRecv, BigDecimal depositActual) {
		Fee fee = new Fee();
		//TODO dateActual是否需要设置
		fee.setAmountRecv(depositRecv.setScale(2, RoundingMode.HALF_UP));
		fee.setAmountActual(depositActual.setScale(2, RoundingMode.HALF_UP));
		if (StringUtils.isNotBlank(agreement.getRoom().getRental())) {
			fee.setRental(BigDecimal.valueOf(Double.valueOf(agreement.getRoom().getRental())).setScale(2, RoundingMode.HALF_UP));
		} else {
			fee.setRental(agreement.getRentPay().setScale(2, RoundingMode.HALF_UP));
		}
		fee.setDateBeginRecv(agreement.getRentBeginDate());
		fee.setDateEndRecv(agreement.getRentEndDate());
		fee.setBalance(BigDecimal.valueOf(0).setScale(2, RoundingMode.HALF_UP));
		fee.setAgreement(agreement);
		fee.setTenantUser(agreement.getTenantUser());
		LandlordOwnerUser ownerUser = null;
		LandlordUser landlordUser = landlordUserService.getLoginUser();
		if (landlordUser == null) {
			ownerUser = agreement.getLandlordUser();
		}else{
			landlordUser = landlordUserService.getLoginUser().getOwnerUser();
			ownerUser = landlordUser.getOwnerUser();
		}
		fee.setLandlordUser(ownerUser);
		fee.setAgent(ownerUser);
		fee.setRoom(agreement.getRoom());
		fee.setDateActual(DateTimeUtil.formatDate(new Date()));
		fee.setPayMode(Fee.TRADE_TYPE_CRASH);
		
		//兼容vc, 目前是非空字段
		fee.setType(1);
		fee.setStatus(LandlordConstant.FEE_STATE_CONFIRMED);
		fee.setFeeType(Fee.FEE_TYPE_DEPOSIT);
		Fee dbFee = genericService.add(fee);
		financeStatementService.autoCreateFinanceStatement(dbFee);
		return dbFee;
	}
	
	/**
	 * 抄表后调用此接口
	 * @param feeRule
	 */
	public void generateMeterFee(FeeRule feeRule) {
		genericService.refresh(feeRule);
		if (feeRule.getMeters() == null || feeRule.getMeters().size() < 2 || feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getType() != FeeRuleType.meter) {
			return ;
		}
		if (feeRule.getRoom() != null && Room.RENT_STATE_ALREADY.equals(feeRule.getRoom().getRentState())) { //已出租状态的房子抄表才收费
			Room dbRoom = feeRule.getRoom();
			FeeRecord feeRecord = getOrGenerateFeeRecordIfNotExists(dbRoom.getAgreement());
			RentalOrder rentalOrder = rentalOrderService.searchRentalOrderByFeeRecord(feeRecord);
			if (feeRecord != null) {
				FeeAdditionRecord feeAdditionRecord = new FeeAdditionRecord();
				feeAdditionRecord.setMeter1(feeRule.getMeter(0));
				feeAdditionRecord.setMeter2(feeRule.getMeter(1));
				feeAdditionRecord.setFeeRuleCfg(feeRule.getFeeRuleCfg());
				if (feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getCalcMode() == FeeRuleCalcMode.threshold && feeAdditionRecord.getMeter1().getCount().subtract(feeAdditionRecord.getMeter2().getCount()).compareTo(feeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getValueLow()) < 0) {
					feeAdditionRecord.setPriceRecv(feeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getValueLow().multiply(feeAdditionRecord.getMeter1().getPrice()));
				} else {
					feeAdditionRecord.setPriceRecv(feeAdditionRecord.getMeter1().getCount().subtract(feeAdditionRecord.getMeter2().getCount()).multiply(feeAdditionRecord.getMeter1().getPrice()));
				}
				feeAdditionRecord.setFeeRecord(feeRecord);
				if (rentalOrder == null) {
					feeAdditionRecord.setStatus(FeeAdditionRecord.STATUS_CONFIRMED);
				} else {
					feeAdditionRecord.setStatus(FeeAdditionRecord.STATUS_NEED_CONFIRM);
				}
				genericService.add(feeAdditionRecord);
				feeRecord.setAmountRecv(feeRecord.getAmountRecv().add(feeAdditionRecord.getPriceRecv()).setScale(2, RoundingMode.HALF_UP));
				genericService.merge(feeRecord);
			}
		} else if (feeRule.getShareUnit() != null) {
			List<RoomShareUnit> roomShareUnits = feeRule.getShareUnit().getRoomShareUnits();
			int daySum = 0;
			List<FeeRecord> feeRecords = new ArrayList<FeeRecord>(roomShareUnits.size());
			List<Integer> dayCounts = new ArrayList<Integer>(roomShareUnits.size());
			for (RoomShareUnit roomShareUnit : roomShareUnits) {
				if (roomShareUnit.getRoom() != null && Room.RENT_STATE_ALREADY.equals(roomShareUnit.getRoom().getRentState())) {
					FeeRecord dbFeeRecord = getOrGenerateFeeRecordIfNotExists(roomShareUnit.getRoom().getAgreement());
					if (dbFeeRecord != null) {
						int intervalDay = (int)DateTimeUtil.getIntervalDays(dbFeeRecord.getDateBeginRecv(), dbFeeRecord.getDateEndRecv()); 
						daySum += intervalDay;
						dayCounts.add(intervalDay);
						feeRecords.add(dbFeeRecord);
					}
				}
			}
			
			for (int i = 0; i < feeRecords.size(); i++) {
				FeeRecord feeRecord = feeRecords.get(i);
				RentalOrder rentalOrder = rentalOrderService.searchRentalOrderByFeeRecord(feeRecord);
				FeeAdditionRecord feeAdditionRecord = new FeeAdditionRecord();
				feeAdditionRecord.setMeter1(feeRule.getMeter(0));
				feeAdditionRecord.setMeter2(feeRule.getMeter(1));
				feeAdditionRecord.setFeeRuleCfg(feeRule.getFeeRuleCfg());
				feeAdditionRecord.setPriceRecv(feeAdditionRecord.getMeter1().getCount().subtract(feeAdditionRecord.getMeter2().getCount()).multiply(feeAdditionRecord.getMeter1().getPrice()).multiply(BigDecimal.valueOf(dayCounts.get(i)).divide(BigDecimal.valueOf(daySum), 2, RoundingMode.HALF_UP)));
				feeAdditionRecord.setFeeRecord(feeRecord);
				if (rentalOrder == null) {
					feeAdditionRecord.setStatus(FeeAdditionRecord.STATUS_CONFIRMED);
				} else {
					feeAdditionRecord.setStatus(FeeAdditionRecord.STATUS_NEED_CONFIRM);
				}
				genericService.add(feeAdditionRecord);
				feeRecord.setAmountRecv(feeRecord.getAmountRecv().add(feeAdditionRecord.getPriceRecv()).setScale(2, RoundingMode.HALF_UP));
				genericService.merge(feeRecord);
			}
		}
	}
	
	public FeeRecord getOrGenerateFeeRecordIfNotExists(ValidAgreement agreement) {
		if (agreement == null) {
			return null;
		}
		FeeRecord dbFeeRecord = null;
		FeeRecord example = new FeeRecord();
		example.setAgreement(agreement);
		Condition condition = new Condition();
		condition.setSort("id");
		condition.setDir("desc");
		dbFeeRecord = genericService.searchByModel(example, condition).getData(0);
		if (dbFeeRecord == null || FeeRecord.FEE_STATUS_RENT_TODO != dbFeeRecord.getStatus()) {
			dbFeeRecord = generateFeeRecord(agreement.getRoom());
		}
		return dbFeeRecord;
	}
	
	public FeeRecord repaireFeeRecords(List<FeeRecord> feeRecords) {
		FeeRecord dblatestFeeRecord = null;
		dblatestFeeRecord = feeRecords.get(0);
		
		if (dblatestFeeRecord != null) {
			Agreement dbAgreement = dblatestFeeRecord.getRoom().getAgreement();
			List<Fee> fees = dbAgreement.getFees();
			
			if (fees != null && fees.size() > 0) {
				if (fees.size() > 1 && fees.get(0).getDateBeginRecv().equals(dblatestFeeRecord.getDateBeginRecv())) {
					boolean canDelete = true;
					Integer orderStatus = getOrderStatus(fees.get(0));
					if (orderStatus != null) {
						if (orderStatus != RentalOrder.ORDER_STATE_WAITING_PAYMENT) {
							canDelete = false;
						}
					}
					if (canDelete) {
						genericService.delete(dblatestFeeRecord);
					}
					dblatestFeeRecord = generateFeeRecord(dbAgreement.getRoom());
				}
			}
		}
		
		
		return dblatestFeeRecord;
	}
	
	/**
	 * 修复押金的开始时间和结束时间
	 */
	public void repairDeposit() {
		QLInfo qlInfo = new QLInfo("select a from " + SimpleAgreement.class.getName() + " a order by a.id desc", true);
		int count = genericService.getCount(qlInfo, false);
		for (int i = 0; i < count; i+= 1000) {
			qlInfo.setFirstResult(i);
			qlInfo.setMaxResults(1000);
			List<SimpleAgreement> agreements = genericService.searchByQl(qlInfo).getData();
			Fee depositFee = null;
			for (SimpleAgreement agreement : agreements) {
				try {
					if (agreement.getFees() != null && agreement.getFees().size() > 0) {
						depositFee = agreement.getFees().get(agreement.getFees().size() - 1);
						if (!depositFee.getDateBeginRecv().equals(DateTimeUtil.completeDateTimeNew(agreement.getRentBeginDate())) || !depositFee.getDateEndRecv().equals(DateTimeUtil.completeDateTimeNew(agreement.getRentEndDate()))) {
							depositFee.setDateBeginRecv(DateTimeUtil.completeDateTimeNew(agreement.getRentBeginDate()));
							depositFee.setDateEndRecv(DateTimeUtil.completeDateTimeNew(agreement.getRentEndDate()));
							genericService.merge(depositFee);
							logger.info("修复押金时间成功！，feeid：" + depositFee.getId());
						}
					}
				} catch(Exception e) {
					logger.error("修复押金时间失败，合约id：" + agreement.getId() + ", 押金feeId：" + depositFee.getId());
				}
			}
		}
	}
	
	
	public boolean repairFeeType() {
		QLInfo qlInfo = new QLInfo("select a from " + SimpleAgreement.class.getName() + " a where exists (from a.fees b where b.feeType is null) order by a.id desc", true);
		int count = genericService.getCount(qlInfo, false);
		for (int i = 0; i <= count; i+= 1000) {
			qlInfo.setFirstResult(0);	//修复后，修复前的数据会没有，所以还是要从0开始
			qlInfo.setMaxResults(1000);
			List<SimpleAgreement> agreements = genericService.searchByQl(qlInfo).getData();
			if (agreements != null && agreements.size() > 0) {
				this.getThis().repairFeeTypeInterval(agreements);
			}
		}
		return true;
	}
	
	@Transactional
	public void repairFeeTypeInterval(List<SimpleAgreement> agreements) {
		/*List<Fee> fees = new ArrayList<Fee>(5 * 1000);*/
		for (SimpleAgreement agreement : agreements) {
			try {
				if (agreement.getFees() != null && agreement.getFees().size() > 0) {
					Fee dbFee = agreement.getFees().get(agreement.getFees().size() - 1);
					dbFee.setFeeType(Fee.FEE_TYPE_DEPOSIT);
					/*fees.add(dbFee);*/
					
					if (agreement.getFees().size() > 1) {
						if (Agreement.AGREEMENT_STATE_VALID.equals(agreement.getAgreementState())) {
							dbFee = agreement.getFees().get(0);
							dbFee.setFeeType(Fee.FEE_TYPE_RENTAL);
							/*fees.add(dbFee);*/
						} else {
							dbFee = agreement.getFees().get(0);
							dbFee.setFeeType(Fee.FEE_TYPE_UNREANTAL);
							/*fees.add(dbFee);*/
						}
						
						for (int j = 1; j < agreement.getFees().size() - 1; j++) {
							dbFee = agreement.getFees().get(j);
							dbFee.setFeeType(Fee.FEE_TYPE_RENTAL);
							/*fees.add(dbFee);*/
						}
					}
				}
			} catch(Exception e) {
				logger.error("修复费用类型失败，合约id：" + agreement.getId(), e);
			}
		}
		
		logger.info("修复费用类型成功，最新的一条agreementId：" + agreements.get(agreements.size() - 1).getId());
		em.flush();
		em.clear();
	}
	
	@Transactional
	public void updateFeeRecordFromAgreement(ValidAgreement dbAgreement, BigDecimal oldDeposit) {
		FeeRecord dbLastestFeeRecord = getOrGenerateFeeRecordIfNotExists(dbAgreement);
		if (dbLastestFeeRecord == null) {
			return ;
		}
		
		if (oldDeposit.compareTo(BigDecimal.valueOf(Double.valueOf(dbAgreement.getDeposit()))) != 0 && dbAgreement.getFees() != null && dbAgreement.getFees().size() >= 1) {
			FeeRuleCfg extraFeeRuleCfg = genericService.load(FeeRuleCfg.class, FeeRuleCfg.FEE_RULE_CFG_EXTRA);
			Meter fixedMeter = genericService.load(Meter.class, 2);
			FeeAdditionRecord depositAdditionRecord = new FeeAdditionRecord();
			depositAdditionRecord.setName("押金（补差）");
			depositAdditionRecord.setPriceRecv(BigDecimal.valueOf(Double.valueOf(dbAgreement.getDeposit())).subtract(oldDeposit).setScale(2, RoundingMode.HALF_UP));
			depositAdditionRecord.setFeeRuleCfg(extraFeeRuleCfg);
			depositAdditionRecord.setMeter1(fixedMeter);
			depositAdditionRecord.setMeter2(fixedMeter);
			depositAdditionRecord.setOverdueFine(false);
			depositAdditionRecord.setLandlordUser(landlordUserService.getLoginUser().getOwnerUser());
			depositAdditionRecord.setId(null);
			depositAdditionRecord.setFeeRecord(dbLastestFeeRecord);
			dbLastestFeeRecord.getFeeAdditionRecords().add(depositAdditionRecord);
			dbLastestFeeRecord.setAmountRecv(dbLastestFeeRecord.getAmountRecv().add(depositAdditionRecord.getPriceRecv()).setScale(2, RoundingMode.HALF_UP));
		}
		
		Fee example = new Fee();
		example.setFeeRecordId(dbLastestFeeRecord.getId());
		Integer orderStatus = getOrderStatus(example);
		if (orderStatus != null) {
			return ; 	//已经生成网上收租单，不需要修复时间和房租。
		}
		
		if (dbAgreement.getFees() == null || dbAgreement.getFees().size() <= 1) {
			//第一笔房租没有收才修复时间为合约开始时间。
			dbLastestFeeRecord.setDateBeginRecv(dbAgreement.getRentBeginDate());
			dbLastestFeeRecord.setDateEndRecv(DateTimeUtil.getFeeEndDate(dbLastestFeeRecord.getDateBeginRecv(), dbAgreement.getPayNum()));
			
			BigDecimal newRental = dbAgreement.getRentPay().multiply(BigDecimal.valueOf(dbAgreement.getPayNum()));
			dbLastestFeeRecord.setAmountRecv(dbLastestFeeRecord.getAmountRecv().add(newRental.subtract(dbLastestFeeRecord.getRental())).setScale(2, RoundingMode.HALF_UP));
			dbLastestFeeRecord.setRental(newRental);
			dbLastestFeeRecord.setRentalCalc(newRental);
		} else {
			dbLastestFeeRecord.setDateEndRecv(DateTimeUtil.getFeeEndDate(dbLastestFeeRecord.getDateBeginRecv(), dbAgreement.getRentCycle() + 1));
			
			BigDecimal newRental = dbAgreement.getRentPay().multiply(BigDecimal.valueOf(dbAgreement.getRentCycle() + 1));
			dbLastestFeeRecord.setAmountRecv(dbLastestFeeRecord.getAmountRecv().add(newRental.subtract(dbLastestFeeRecord.getRental())).setScale(2, RoundingMode.HALF_UP));
			dbLastestFeeRecord.setRental(newRental);
			dbLastestFeeRecord.setRentalCalc(newRental);
		}
		feeRecordService.repairedFeeRecordByRoom(dbAgreement.getRoom());
	}
	
}